package cn.bitkit.component.redis;

import cn.bitkit.component.context.SpringContext;
import cn.bitkit.tools.common.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;

import java.time.Duration;
import java.util.Collections;

/**
 * 	使用redis实现锁
 * @author changbo
 *
 */
@Slf4j
public class RedisLock {
	
	public static boolean retryLock(String lockKey, String lockId, long timeout) {
		boolean lock;
		int index = 0;
		while (true){
			lock = tryLock(lockKey, lockId, timeout);
			if(lock || ++index >= 10){
				break;
			}
			ThreadUtil.sleep(500);
		}
		return lock;
	}

	public static boolean tryLock(String lockKey, String lockId, long timeout) {
		try {
			StringRedisTemplate stringRedisTemplate = SpringContext.getAssertedBean(StringRedisTemplate.class);
			return Boolean.TRUE.equals(stringRedisTemplate.opsForValue().setIfAbsent(lockKey, lockId, Duration.ofMillis(timeout)));
		}catch (Exception e) {
			log.error("", e);
		}
		return false;
	}
	
	public static void release(String lockKey, String lockId) {
		try {
			StringRedisTemplate stringRedisTemplate = SpringContext.getAssertedBean(StringRedisTemplate.class);
            String luaScript = """
                    if redis.call('get', KEYS[1]) == ARGV[1]
                    then return redis.call('del', KEYS[1])
                    else return 0
                    end
                    """;
            DefaultRedisScript<Long> script = new DefaultRedisScript<>();
            script.setScriptText(luaScript);
            script.setResultType(Long.class);
			stringRedisTemplate.execute(script, Collections.singletonList(lockKey), lockId);
		}catch (Exception e) {
			log.error("", e);
		}
	}
	
}
